﻿/* 
Copyright 2008 William C. Pierce 

Licensed under the Apache License, Version 2.0 (the "License"); 
you may not use this file except in compliance with the License. 
You may obtain a copy of the License at 

	http://www.apache.org/licenses/LICENSE-2.0 

Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
See the License for the specific language governing permissions and 
limitations under the License. 
*/

import System
import System.Type as Typ
import System.Collections
import System.Reflection
import Iesi.Collections.Generic
import log4net;
import NHibernate
import NHibernate.Bytecode
import NHibernate.Engine
import NHibernate.Proxy
import NHibernate.Proxy.Poco.Castle
import NHibernate.Type

class StaticProxyFactory(IProxyFactory):
	static final _log as ILog
	static final _proxies as IDictionary
		
	_entityName as string
	_persistentClass as Typ
	_interfaces as (Typ)
	_getIdentifierMethod as MethodInfo
	_setIdentifierMethod as MethodInfo
	_componentIdType as IAbstractComponentType
	_isClassProxy as bool
	_proxyKey as long
	_proxyType as Typ
	
	static def constructor():
		_log = LogManager.GetLogger(typeof(StaticProxyFactory))
		_proxies = Hashtable()
{0}
	
	def PostInstantiate(entityName as string, persistentClass as Typ, interfaces as ISet of Typ, getIdentifierMethod as MethodInfo, setIdentifierMethod as MethodInfo, componentIdType as IAbstractComponentType):
		_entityName = entityName;
		_persistentClass = persistentClass
		_interfaces = array(Typ, interfaces.Count)
		interfaces.CopyTo( _interfaces, 0 )
		_getIdentifierMethod = getIdentifierMethod
		_setIdentifierMethod = setIdentifierMethod
		_componentIdType = componentIdType
		_isClassProxy = _interfaces.Length == 1

		if _isClassProxy:
			_proxyKey = _persistentClass.FullName.GetHashCode()
			_log.Debug(_persistentClass.FullName)
		else:
			_proxyKey = _interfaces[0].FullName.GetHashCode()
			_log.Debug(_interfaces[0].FullName)

		for iface in _interfaces:
			_log.Debug(iface.FullName)
			_proxyKey = 29 * _proxyKey + iface.FullName.GetHashCode()
			_log.Debug(_proxyKey)
			
		_proxyType = _proxies[_proxyKey] as Typ
	
	def GetProxy(id as object, session as ISessionImplementor) as INHibernateProxy:
		proxy as INHibernateProxy
		try:
			generatedProxy as object
			initializer as CastleLazyInitializer = CastleLazyInitializer(_entityName, _persistentClass, id, _getIdentifierMethod, _setIdentifierMethod, _componentIdType, session)
			interceptors as (Castle.Core.Interceptor.IInterceptor) = array(Castle.Core.Interceptor.IInterceptor, 1)
			interceptors[0] = initializer
			
			if _isClassProxy:
				generatedProxy = Activator.CreateInstance(_proxyType, interceptors )
			else:
				generatedProxy = Activator.CreateInstance(_proxyType, interceptors, object() )
			
			initializer._constructed = true
			proxy = cast(INHibernateProxy, generatedProxy)
		except e:
			_log.Error("Creating a proxy instance failed", e)
			raise HibernateException("Creating a proxy instance failed", e)
		return proxy
		
class StaticProxyFactoryFactory(IProxyFactoryFactory):
	def BuildProxyFactory() as IProxyFactory:
		return StaticProxyFactory()
		
[assembly: System.Security.AllowPartiallyTrustedCallers]